package com.thinkit.bigdata.web.controller.cronTask;

import com.google.common.base.Strings;
import com.thinkit.bigdata.core.ConfigHelper;
import com.thinkit.bigdata.core.util.DateFormatUtil;
import com.thinkit.bigdata.core.util.FtpUtil;
import com.thinkit.bigdata.core.util.TaskUtil;
import com.thinkit.bigdata.core.util.es.ESUtil;
import com.thinkit.bigdata.web.controller.pubmet.PubMethod;
import com.thinkit.bigdata.web.coremet.SystemStatic;
import com.thinkit.bigdata.web.model.BaseEntity;
import com.thinkit.bigdata.web.model.bus.*;
import com.thinkit.bigdata.web.model.es.audioEs.*;
import com.thinkit.bigdata.web.model.es.countEs.CountModelRules;
import com.thinkit.bigdata.web.model.es.countEs.CountSource;
import com.thinkit.bigdata.web.model.result.Constants;
import com.thinkit.bigdata.web.service.bus.BusModelRuleService;
import com.thinkit.bigdata.web.service.bus.BusModelService;
import com.thinkit.bigdata.web.service.bus.BusWorkModelService;
import com.thinkit.bigdata.web.service.bus.BusWorkService;
import com.thinkit.bigdata.web.service.sys.SysConfigService;
import net.sf.json.JSONObject;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.DateConverter;
import org.apache.log4j.Logger;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * 质检任务相关定时任务
 * Created by hccl on 2018/9/14.
 */
@Component
public class QualityCronTask {

    private static Logger logger = Logger.getLogger(QualityCronTask.class);

    @Resource
    private ESUtil esUtil;

    @Resource
    private BusWorkService busWorkService;

    @Resource
    private BusWorkModelService workModelService;

    @Resource
    private BusModelService modelService;

    @Resource
    private SysConfigService sysConfigService;

    @Resource
    private BusModelRuleService busModelRuleService;

    //获取时间
    private Map<String, String> pubMethodTime(String logTxt) {
        int day = -1;
        Date date = new Date();
        logger.info(logTxt + "当前日期：" + DateFormatUtil.dateToString(date, DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
        Date yesterday = DateFormatUtil.addNDay(date, day);
        logger.info(logTxt + day + "天之前日期：" + DateFormatUtil.dateToString(date, DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
        String yesterdayStr = DateFormatUtil.dateToString(yesterday, DateFormatUtil.yyyy_MM_dd);
        String startTime = yesterdayStr + " 00:00:00";
        String endTime = yesterdayStr + " 23:59:59";
        logger.info(logTxt + "startTime =" + startTime);
        logger.info(logTxt + "endTime = " + endTime);
        Map<String, String> timeMap = new HashMap<>();
        timeMap.put("startTime", startTime);
        timeMap.put("endTime", endTime);
        return timeMap;
    }

    //根据时间获取es数据
    private List<Source> pubMethodSource(String logTxt, String startTime, String endTime) {
        //根据修改时间查询数据
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        QueryBuilder queryBuilder = QueryBuilders.rangeQuery("workScores.updateTime").gte(startTime).lte(endTime);
        boolQuery.must(QueryBuilders.nestedQuery("workScores", queryBuilder, ScoreMode.None));
        String[] includes = new String[]{"workScores.workId"};
        List<Source> sourceList = getSourceByIncludes(logTxt, boolQuery, includes);
        if (sourceList.isEmpty()) {
            logger.info(logTxt + "昨天没有修改的数据");
            return sourceList;
        }
        return sourceList;
    }

    //获取任务id
    private List<Long> pubMethod(List<Source> sources) {
        List<Long> taskList = new ArrayList<>();
        for (Source source : sources) {
            for (WorkScores workScores : source.getWorkScores()) {
                if (!taskList.contains(workScores.getWorkId())) {
                    taskList.add(workScores.getWorkId());
                }
            }
        }
        return taskList;
    }

    //获取通话时间最大值最小值
    private Map<String, String> pubMetMaxMinTime(String logTxt, Long workId) {
        //根据修改时间查询数据
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        QueryBuilder queryBuilder = QueryBuilders.matchQuery("workScores.workId", workId);
        boolQuery.must(QueryBuilders.nestedQuery("workScores", queryBuilder, ScoreMode.None));
        String[] includes = new String[]{
                "voiceInfo.callStartTime",
                "voiceInfo.callEndTime"
        };
        List<Source> sourceList = getSourceByIncludes(logTxt, boolQuery, includes);
        logger.info("获取数据条数为：" + sourceList.size());
        if (sourceList.isEmpty()) {
            logger.info(logTxt + "昨天没有修改的数据");
            return null;
        }
        Map<String, String> map = new HashMap<>();
        String minTime = sourceList.get(0).getVoiceInfo().getCallStartTime();
        String maxTime = sourceList.get(0).getVoiceInfo().getCallEndTime();
        for (int i = 0; i < sourceList.size() - 1; i++) {
            //min
            if (DateFormatUtil.stringToDate(sourceList.get(i).getVoiceInfo().getCallStartTime(), DateFormatUtil.yyyy_MM_dd_HH_mm_ss).getTime()
                    <= DateFormatUtil.stringToDate(sourceList.get(i + 1).getVoiceInfo().getCallStartTime(), DateFormatUtil.yyyy_MM_dd_HH_mm_ss).getTime()) {
                minTime = sourceList.get(i).getVoiceInfo().getCallStartTime();
            }
            //max
            if (DateFormatUtil.stringToDate(sourceList.get(i).getVoiceInfo().getCallStartTime(), DateFormatUtil.yyyy_MM_dd_HH_mm_ss).getTime()
                    >= DateFormatUtil.stringToDate(sourceList.get(i + 1).getVoiceInfo().getCallStartTime(), DateFormatUtil.yyyy_MM_dd_HH_mm_ss).getTime()) {
                maxTime = sourceList.get(i).getVoiceInfo().getCallStartTime();
            }
        }
        map.put("minTime", minTime);
        map.put("maxTime", maxTime);
        return map;
    }

    //计算通话时间的最大值和最小值，相差几个月
    private static Integer pubMethodIntervalMonth(String minTime, String maxTime) {
        return DateFormatUtil.intervalMonth(
                DateFormatUtil.stringToDate(minTime, DateFormatUtil.yyyy_MM_dd_HH_mm_ss),
                DateFormatUtil.stringToDate(maxTime, DateFormatUtil.yyyy_MM_dd_HH_mm_ss)
        );
    }

//    @Scheduled(cron = "${cron.quality.task:0 0 5 * * ?}")
    @Scheduled(cron = "0 0 5 * * ?")
    public void cronPreTask() {
        String logTxt = "【质检任务考核分数统计】";
        logger.info(logTxt + "启动");
        boolean start = true;
        try {
            start = FtpUtil.sendCcs("cronPreTask", logTxt);
        } catch (IOException e) {
            logger.error(logTxt + Arrays.toString(e.getStackTrace()));
        }
        if (!start) {
            logger.info(logTxt + "该方法其他机器有启动");
            return;
        }
        //获取时间
        Map<String, String> timeMap = pubMethodTime(logTxt);
        //根据时间获取es数据
        List<Source> list;
        try {
            list = pubMethodSource(logTxt, timeMap.get("startTime"), timeMap.get("endTime"));
        } catch (Exception e) {
            logger.error(logTxt + Arrays.toString(e.getStackTrace()));
            return;
        }
        if (list.isEmpty()) {
            return;
        }
        //获取任务id
        List<Long> taskList = pubMethod(list);
        if (taskList.isEmpty()) {
            return;
        }
        for (Long taskId : taskList) {
            logger.info(logTxt + "workId = " + taskId);
            BusWork busWork = busWorkService.selectByPrimaryKey(taskId);
            if (busWork == null) {
                continue;
            }
            String logTxtStr = "自动";
            String taskType = "auto";
            String cycleAssess = null;
            List<Map<String, String>> timeList = new ArrayList<>();
            if (busWork.getWorktype() == BaseEntity.PREQUALITY_AUTO) {//自动质检
                //获取通话时间最大值最小值
                Map<String, String> maxMinTime;
                try {
                    maxMinTime = pubMetMaxMinTime(logTxt, taskId);
                } catch (Exception e) {
                    logger.error(logTxtStr + logTxt + Arrays.toString(e.getStackTrace()));
                    continue;
                }
                if (maxMinTime == null) {
                    continue;
                }
                //计算通话时间的最大值和最小值，相差几个月
                Integer intervalMonth = pubMethodIntervalMonth(maxMinTime.get("minTime"), maxMinTime.get("maxTime"));
                timeList = formatAssWork(busWork, intervalMonth, maxMinTime.get("minTime"), maxMinTime.get("maxTime"));
                cycleAssess = busWork.getEvalcyclestart() + "-" + busWork.getEvalcycleend();
            } else if (busWork.getWorktype() == BaseEntity.PREQUALITY_PRE) {
                logTxtStr = "预";
                Map<String, String> maxMinTime = new HashMap<>();
                String startTime = DateFormatUtil.dateToString(busWork.getCallstarttime(), DateFormatUtil.yyyy_MM_dd_HH_mm_ss);
                maxMinTime.put("start", startTime);
                String endTime = DateFormatUtil.dateToString(busWork.getCallendtime(), DateFormatUtil.yyyy_MM_dd_HH_mm_ss).trim();
                maxMinTime.put("end", endTime);
                timeList.add(maxMinTime);
                taskType = "pre";
            } else {
                continue;
            }
            for (Map<String, String> time : timeList) {
                try {
                    pubMethodS(logTxtStr + logTxt, busWork, time.get("start"), time.get("end"), taskType, cycleAssess);
                } catch (Exception e) {
                    logger.error(logTxtStr + logTxt + Arrays.toString(e.getStackTrace()));
                    e.printStackTrace();
                }
            }
        }
    }

    //查询特定字段es数据
    private List<Source> getSourceByIncludes(String logTxt, BoolQueryBuilder boolQuery, String[] includes) {
        List<Source> sourceList = new ArrayList<>();
        //总条数
        Integer sum = SystemStatic.crud.queryQBuilderAllByMes(SystemStatic.AUDIO_ES_INDEX, SystemStatic.AUDIO_ES_TYPE, boolQuery);
        logger.info(logTxt + "sum = " + sum);
        if (sum == 0) {
            return sourceList;
        }
        //每次查询条数
        int excleMax = ConfigHelper.getInt("export.data.sheet.max.number", 1000);
        List<Integer> pageTount = TaskUtil.formatSum(sum, excleMax);//todo最后一个数字需要特殊处理:6022
        //分页查询数据
        for (Integer pageNum : pageTount) {
            List<String> docList = SystemStatic.crud.queryMapQBuilderRetRuleAndWork(
                    SystemStatic.AUDIO_ES_INDEX,
                    SystemStatic.AUDIO_ES_TYPE,
                    pageNum,
                    excleMax,
                    boolQuery,
                    "",
                    "",
                    includes
            );
            logger.info("获取数据条数为：" + docList.size());
            if (docList.isEmpty()) continue;
            sourceList.addAll(esUtil.strs2Entitys(docList));
        }
        return sourceList;
    }

    //根据考核周期获取音频信息
    private List<Source> getSourByMinMax(String logTxt, BusWork busWork, String startTime, String endTime) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        PubMethod.formatTime(boolQuery, startTime, endTime);
        boolQuery.must(QueryBuilders.nestedQuery("workScores",
                QueryBuilders.matchQuery("workScores.workId", busWork.getId()),
                ScoreMode.None)
        );
        String[] includes = new String[]{
                "serialNumber",
                "voiceInfo.groupId",
                "voiceInfo.seatGroup",
                "voiceInfo.seatId",
                "voiceInfo.seatName",
                "ruleInfos.ruleId",
                "ruleInfos.ruleTimes",
                "workScores.workId",
                "workScores.workName",
                "workScores.workScore",
                "workScores.modelRules"
        };
        List<Source> sourceList = getSourceByIncludes(logTxt, boolQuery, includes);
        if (sourceList.isEmpty()) {
            logger.info(logTxt + "获取所有【" + busWork.getWorkname() + "】任务失败");
            return sourceList;
        }
        return sourceList;
    }

    //根据坐席工号分任务统计
    private Map<String, List<Source>> groupSourceBySeatId(List<Source> sourceList, BusWork busWork) {
        Map<String, List<Source>> map = new HashMap<>();
        List<String> seatIds = groupSeatIdByEs(sourceList, busWork);
        for (String seatId : seatIds) {
            List<Source> list = new ArrayList<>();
            for (Source source : sourceList) {
                if (source.getVoiceInfo().getSeatId().equals(seatId)) {
                    list.add(source);
                }
            }
            map.put(seatId, list);
        }
        return map;
    }

    //todo获取工号应该在es中获取，mysql中数据有缺失
    //获取任务对应得坐席工号
    private List<String> groupSeatIdByEs (List<Source> sourceList, BusWork busWork) {
        List<String> seatIds = new ArrayList<>();
        //坐席不为空关 - 直接拿数据库中的工号
        if (!Strings.isNullOrEmpty(busWork.getSeatids())) {
            seatIds.addAll(Arrays.asList(busWork.getSeatids().split(",")));
        } else {
            for (Source source : sourceList) {
                if (!seatIds.contains(source.getVoiceInfo().getSeatId())) {
                    seatIds.add(source.getVoiceInfo().getSeatId());
                }
            }
        }
        return seatIds;
    }

    private void pubMethodS(
            String logTxt, BusWork busWork, String startTime, String endTime,
            String TaskType, String cycleAssess
    ) throws InvocationTargetException, IllegalAccessException, IOException {
        //根据考核周期获取音频信息
        List<Source> sourceList = getSourByMinMax(logTxt, busWork, startTime, endTime);
        logger.info(logTxt + "sourceList.size() = " + sourceList.size());
        //根据坐席工号分任务统计
        Map<String, List<Source>> map = groupSourceBySeatId(sourceList, busWork);
        logger.info(logTxt + "seatId.size() = " + map.size());
        for (Map.Entry<String, List<Source>> entry : map.entrySet()) {
            logger.info(logTxt + "seatId = " + entry.getKey() + ", source.size = " + entry.getValue().size());
            if (entry.getValue().isEmpty()) {
                continue;
            }
            CountSource countSource = new CountSource();
            countSource.setId(UUID.randomUUID().toString());
            countSource.setProvince(busWork.getProvincecode());
            countSource.setWorkId(busWork.getId());
            countSource.setWorkName(busWork.getWorkname());
            Long monthAss = null;
            if ("auto".equals(TaskType)) {
                //考核年月   考试开始  结束日期
                Calendar eDataCalA = Calendar.getInstance();
                eDataCalA.setTime(DateFormatUtil.stringToDate(startTime, DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
                monthAss = Long.parseLong(eDataCalA.get(Calendar.YEAR) + "" + formatMonth(eDataCalA.get(Calendar.MONTH) + 1));
                countSource.setMonthlyAssess(monthAss);
            }
            countSource.setMonthlyAssess(monthAss);
            countSource.setCycleAssess(cycleAssess);
            countSource.setAssStartDate(startTime);
            countSource.setAssEndDate(endTime);
            countSource.setInputTime(DateFormatUtil.dateToString(new Date(), DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
            countSource.setGroupId(entry.getValue().get(0).getVoiceInfo().getGroupId());
            countSource.setGroupName(entry.getValue().get(0).getVoiceInfo().getSeatGroup());
            countSource.setSeatId(entry.getValue().get(0).getVoiceInfo().getSeatId());
            countSource.setSeatName(entry.getValue().get(0).getVoiceInfo().getSeatName());
            countSource.setAudioSum(audioSum(countSource));
            List<CountModelRules> modelRulesList = new ArrayList<>();
            int audioScoreflag = 0;
            Long modelId = null;
            //将相同的rule装载
            List<ModelRulesDto> dtoList = new ArrayList<>();
            for (Source source : entry.getValue()) {
                for (WorkScores workScores : source.getWorkScores()) {
                    if (!busWork.getId().toString().equals(workScores.getWorkId().toString())) {
                        continue;
                    }
                    audioScoreflag += workScores.getWorkScore();
                    if (workScores.getModelRules() == null || workScores.getModelRules().isEmpty()) {
                        continue;
                    }
                    for (ModelRules mr : workScores.getModelRules()) {
                        ModelRulesDto dto = new ModelRulesDto();
                        ConvertUtils.register(new DateConverter(null), java.util.Date.class);
                        BeanUtils.copyProperties(dto, mr);
                        if (!dtoList.contains(dto)) {
                            dtoList.add(dto);
                        }
                        modelId = mr.getModelId();
                    }
                }
            }
            if (modelId == null) {//一条音频都没有匹配到
                //查询模型总分
                BusWorkModelExample example = new BusWorkModelExample();
                example.createCriteria().andWorkidEqualTo(busWork.getId());
                BusModel model = modelService.selectByPrimaryKey(workModelService.selectByExample(example).get(0).getModelid());
                countSource.setWorkScore(model.getFullscore());
                //遍历模型用到的所有规则
                BusModelRuleExample example1 = new BusModelRuleExample();
                example1.createCriteria().andModelidEqualTo(model.getId());
                List<BusModelRule> modelRuleList = busModelRuleService.selectByExample(example1);
                for (BusModelRule modelRule : modelRuleList) {
                    CountModelRules modelRules = new CountModelRules();
                    modelRules.setModelId(modelRule.getModelid());
                    modelRules.setModelName(model.getName());
                    modelRules.setRuleId(modelRule.getRuleid());
                    modelRules.setRuleName(modelRule.getRulename());
                    modelRules.setUseFor(modelRule.getUserfor());
                    modelRules.setUpdateTime(DateFormatUtil.dateToString(new Date(), DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
                    modelRules.setRuleTimes(0);
                    modelRules.setFateful(modelRule.getFateful());
                    //致命性
                    if (modelRule.getSignscore() == BaseEntity.SIGNSCORE_ADD) {//加分项规则
                        //致命性
                        modelRules.setFateful(BaseEntity.FATEFUL_ADD);
                    }
                    modelRules.setScore(0);
                    if (busWork.getScoreflag() == BaseEntity.SCORE_FLAG_TASK) {
                        modelRules.setScore(0);
                    } else {
                        modelRules.setScore(model.getFullscore());
                    }
                    modelRulesList.add(modelRules);
                }
            } else {
                //满分
                BusModel model = modelService.selectByPrimaryKey(modelId);
                if (model == null) {
                    return;
                }
                int fullScore = 100;
                if (model.getFullscore() != null) {
                    fullScore = model.getFullscore();
                }
                Integer sum = 0;
                //致命性规则并且分数上限为空
                boolean fatefulAndMaxScore = false;
                //装载质检结果，计算命中音量，分值和致命性量
                for (ModelRulesDto rules : dtoList) {
                    CountModelRules modelRules = new CountModelRules();
                    modelRules.setModelId(rules.getModelId());
                    modelRules.setModelName(rules.getModelName());
                    modelRules.setRuleId(rules.getRuleId());
                    modelRules.setRuleName(rules.getRuleName());
                    modelRules.setUseFor(rules.getUseFor());
                    modelRules.setUpdateTime(DateFormatUtil.dateToString(new Date(), DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
                    //命中语音量
                    int ruleAudioTimes;
                    //规则命中总量
                    int ruleTimes = 0;
                    for (Source source : entry.getValue()) {
                        if (source.getRuleInfos() == null || source.getRuleInfos().isEmpty()) {
                            continue;
                        }
                        for (RuleInfos infos : source.getRuleInfos()) {
                            if (rules.getRuleId().toString().equals(infos.getRuleId().toString())) {
                                ruleTimes = infos.getRuleTimes();
                            }
                        }
                    }
                    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
                    boolQuery.must(QueryBuilders.matchQuery("voiceInfo.seatId", countSource.getSeatId()));
                    boolQuery.must(QueryBuilders.matchQuery("voiceInfo.seatName", countSource.getSeatName()));
                    PubMethod.formatTime(boolQuery, startTime, endTime);
                    boolQuery.must(
                            QueryBuilders.nestedQuery(
                                    "workScores",
                                    QueryBuilders.boolQuery()
                                            .must(QueryBuilders.matchQuery("workScores.workId", countSource.getWorkId()))
                                            .must(
                                                    QueryBuilders.nestedQuery(
                                                            "workScores.modelRules",
                                                            QueryBuilders.matchQuery("workScores.modelRules.ruleId", rules.getRuleId()),
                                                            ScoreMode.None

                                                    )
                                            ),
                                    ScoreMode.None
                            )
                    );
                    ruleAudioTimes = SystemStatic.crud.queryQBuilderAllByMes(SystemStatic.AUDIO_ES_INDEX, SystemStatic.AUDIO_ES_TYPE, boolQuery);
                    modelRules.setRuleTimes(ruleAudioTimes);
                    //根据规则id获取规则模型信息
                    BusModelRuleExample example = new BusModelRuleExample();
                    example.createCriteria().andRuleidEqualTo(rules.getRuleId()).andModelidEqualTo(modelId);
                    List<BusModelRule> busModelRules = busModelRuleService.selectByExample(example);
                    BusModelRule busModelRule = busModelRules.get(0);
                    modelRules.setFateful(rules.getFateful());
                    //致命性
                    if (busModelRule.getSignscore() == BaseEntity.SIGNSCORE_ADD) {//加分项规则
                        //致命性
                        modelRules.setFateful(BaseEntity.FATEFUL_ADD);
                    }
                    modelRules.setScore(esUtil.formatModelRuleScoure(
                            rules.getScorePerTime(),
                            rules.getFateful(),
                            ruleTimes,
                            busModelRule.getMaxscore(),
                            fullScore
                    ));
                    modelRulesList.add(modelRules);
                    sum += modelRules.getScore();
                    //致命性规则并且分数上限为空
                    if (busModelRule.getFateful() == BaseEntity.FATEFUL_ART && busModelRule.getMaxscore() == null) {
                        fatefulAndMaxScore = true;
                    }
                }
                if (busWork.getScoreflag() == BaseEntity.SCORE_FLAG_TASK) {
                    int all = fullScore + sum <= 0 ? 0 : (fullScore + sum);
                    countSource.setWorkScore(fatefulAndMaxScore ? 0 : all);
                } else {
                    countSource.setWorkScore((audioScoreflag / entry.getValue().size()));
                }
            }
            countSource.setModelRules(modelRulesList);
            //查看库中是否存在
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            boolQueryBuilder.must(QueryBuilders.matchQuery("groupName", countSource.getGroupName()))
                    .must(QueryBuilders.matchQuery("province", countSource.getProvince()))
                    .must(QueryBuilders.rangeQuery("assStartDate").gte(countSource.getAssStartDate()))
                    .must(QueryBuilders.rangeQuery("assEndDate").lte(countSource.getAssEndDate()))
                    .must(QueryBuilders.matchQuery("workName", countSource.getWorkName()));
            if ("auto".equals(TaskType)) {
                boolQueryBuilder.must(QueryBuilders.matchQuery("monthlyAssess", countSource.getMonthlyAssess()));
            }
            if (!SystemStatic.crud.indexExists(SystemStatic.COUNT_ES_INDEX)) {
                SystemStatic.crud.createIndex(SystemStatic.COUNT_ES_INDEX);
            }
            if (!SystemStatic.crud.typeExists(SystemStatic.COUNT_ES_INDEX, SystemStatic.COUNT_ES_TYPE)) {
                SystemStatic.crud.createMapperByCount(SystemStatic.COUNT_ES_INDEX, SystemStatic.COUNT_ES_TYPE);
            }
            List<String> docList = SystemStatic.crud.queryMapQBuilderList(
                    SystemStatic.COUNT_ES_INDEX,
                    SystemStatic.COUNT_ES_TYPE,
                    0,
                    SystemStatic.crud.queryQBuilderAllByMes(SystemStatic.COUNT_ES_INDEX, SystemStatic.COUNT_ES_TYPE, boolQueryBuilder),
                    boolQueryBuilder,
                    "",
                    ""
            );
            //todo 有时间可以用script局部更新优化
            if (!docList.isEmpty()) {
                countSource.setId(esUtil.str2entity1(docList.get(0)).getId());
                updateSource(countSource, SystemStatic.COUNT_ES_INDEX, SystemStatic.COUNT_ES_TYPE);
            } else {
                SystemStatic.crud.insertDataByCount(SystemStatic.COUNT_ES_INDEX, SystemStatic.COUNT_ES_TYPE, countSource);
            }
        }
    }

    /**
     * 获取任务对应的全部音频
     * @param countSource -
     * @return -
     */
    private static int audioSum(CountSource countSource) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.matchQuery("voiceInfo.seatId", countSource.getSeatId()))
                .must(QueryBuilders.matchQuery("voiceInfo.provinceCode", countSource.getProvince()))
                .must(QueryBuilders.matchQuery("voiceInfo.seatGroup", countSource.getGroupName()))
                .must(
                        QueryBuilders.nestedQuery(
                                "workScores",
                                QueryBuilders.matchQuery("workScores.workId", countSource.getWorkId()),
                                ScoreMode.None
                        )
                );
        return SystemStatic.crud.queryQBuilderAllByMes(SystemStatic.AUDIO_ES_INDEX, SystemStatic.AUDIO_ES_TYPE, boolQuery);
    }

    private static void updateSource(CountSource source, String index, String type) {
        RestStatus status = SystemStatic.crud.updateIndex(index, type, JSONObject.fromObject(source).toString(), source.getId());
        logger.info("数据更新,状态码为【" + status.getStatus() + "】");
    }

    private static String dayFormat(int year, int month, Integer day) {
        Calendar c = Calendar.getInstance();
        c.set(year, month, 0); //输入类型为int类型
        int dayOfMonth = c.get(Calendar.DAY_OF_MONTH);
        logger.info(year + "年" + month + "月有" + dayOfMonth + "天");
        if (day != null && day < dayOfMonth) {
            return day.toString();
        }
        if (dayOfMonth + "".length() == 1) {
            return "0" + dayOfMonth;
        }
        return dayOfMonth + "";
    }

    /**
     * 根据音频时间确定查询的考核周期范围时间条件
     *
     * @param busWork  -
     * @param interval -
     * @param minTime  -
     * @param maxTime  -
     * @return "2018-12-12 11:11:11", "2019-01-18 11:11:11"
     * start = 1    end = 31
     * 2018-12-01 00:00:00    -     2018-12-31 23:59:59
     * 2019-01-01 00:00:00    -     2019-01-31 23:59:59
     * start = 15    end = 14
     * 2018-11-15 00:00:00    -     2018-11-14 23:59:59
     * 2018-12-15 00:00:00    -     2018-12-14 23:59:59
     * 2019-01-15 00:00:00    -     2019-01-14 23:59:59
     * <p>
     * "2018-07-12 11:11:11", "2018-09-18 11:11:11"
     * start = 1    end = 31
     * 2018-07-01 00:00:00    -     2018-07-31 23:59:59
     * 2018-08-01 00:00:00    -     2018-08-31 23:59:59
     * 2018-09-01 00:00:00    -     2018-09-31 23:59:59
     * start = 15    end = 14
     * 2018-06-15 00:00:00    -     2018-07-14 23:59:59
     * 2018-07-15 00:00:00    -     2018-08-14 23:59:59
     * 2018-08-15 00:00:00    -     2018-09-14 23:59:59
     * 2018-09-15 00:00:00    -     2018-10-14 23:59:59
     * <p>
     * "2018-07-16 11:11:11", "2018-09-12 11:11:11"
     * start = 1    end = 31
     * 2018-07-01 00:00:00    -    2018-07-31 23:59:59
     * 2018-08-01 00:00:00    -    2018-08-31 23:59:59
     * 2018-09-01 00:00:00    -    2018-09-31 23:59:59
     * start = 15    end = 14
     * 2018-07-15 00:00:00    -    2018-08-14 23:59:59
     * 2018-08-15 00:00:00    -    2018-09-14 23:59:59
     * <p>
     * "2018-07-12 11:11:11", "2018-09-14 11:11:11"
     * start = 1    end = 31
     * 2018-07-01 00:00:00    -    2018-07-31 23:59:59
     * 2018-08-01 00:00:00    -    2018-08-31 23:59:59
     * 2018-09-01 00:00:00    -    2018-09-31 23:59:59
     * start = 15    end = 14
     * 2018-06-15 00:00:00    -    2018-07-14 23:59:59
     * 2018-07-15 00:00:00    -    2018-08-14 23:59:59
     * 2018-08-15 00:00:00    -    2018-09-14 23:59:59
     * <p>
     * "2018-07-16 11:11:11", "2018-09-19 11:11:11"
     * start = 1    end = 31
     * 2018-07-01 00:00:00    -    2018-07-31 23:59:59
     * 2018-08-01 00:00:00    -    2018-08-31 23:59:59
     * 2018-09-01 00:00:00    -    2018-09-31 23:59:59
     * start = 15    end = 14
     * 2018-07-15 00:00:00    -    2018-08-14 23:59:59
     * 2018-08-15 00:00:00    -    2018-09-14 23:59:59
     * 2018-09-15 00:00:00    -    2018-10-14 23:59:59
     * <p>
     * "2018-07-12 11:11:11", "2018-07-14 11:11:11"
     * start = 1    end = 31
     * 2018-07-01 00:00:00    -    2018-07-31 23:59:59
     * start = 15    end = 14
     * 2018-06-15 00:00:00    -    2018-07-14 23:59:59
     * <p>
     * "2018-07-16 11:11:11", "2018-07-19 11:11:11"
     * start = 1    end = 31
     * 2018-07-01 00:00:00    -    2018-07-31 23:59:59
     * start = 15    end = 14
     * 2018-07-15 00:00:00    -    2018-08-14 23:59:59
     * <p>
     * "2018-07-12 11:11:11", "2018-07-18 11:11:11"
     * start = 1    end = 31
     * 2018-07-01 00:00:00    -    2018-07-31 23:59:59
     * start = 15    end = 14
     * 2018-06-15 00:00:00    -    2018-07-14 23:59:59
     * 2018-07-15 00:00:00    -    2018-08-14 23:59:59
     */
    private static List<Map<String, String>> formatAssWork(BusWork busWork, Integer interval, String minTime, String maxTime) {
        List<Map<String, String>> timeList = new ArrayList<>();
        Integer start = busWork.getEvalcyclestart();
        Integer end = busWork.getEvalcycleend();
        Date eData = DateFormatUtil.stringToDate(minTime, DateFormatUtil.yyyy_MM_dd_HH_mm_ss);
        Calendar eDataCal = Calendar.getInstance();
        eDataCal.setTime(eData);
        if (interval == 0) {
            Map<String, String> time = new HashMap<>();
            if (start < end) {
                Date date = DateFormatUtil.addMonth(eData, 0);
                Calendar dateCal = Calendar.getInstance();
                dateCal.setTime(date);
                int year = dateCal.get(Calendar.YEAR);
                int month = dateCal.get(Calendar.MONTH) + 1;
                time.put("start", dateCal.get(Calendar.YEAR) + "-" + formatMonth(dateCal.get(Calendar.MONTH) + 1) + "-" + dayFormat(year, month, 1) + " 00:00:00");
                time.put("end", dateCal.get(Calendar.YEAR) + "-" + formatMonth(dateCal.get(Calendar.MONTH) + 1) + "-" + dayFormat(year, month, null) + " 23:59:59");
                timeList.add(time);
            }
        }
        for (int i = 0; i < interval; i++) {
            Map<String, String> time = new HashMap<>();
            if (start >= end) {//前一个月到这个月
                Date staDate = DateFormatUtil.addMonth(eData, i);
                Date endDate = DateFormatUtil.addMonth(eData, (i + 1));
                Calendar staDateCal = Calendar.getInstance();
                staDateCal.setTime(staDate);
                Calendar endDateCal = Calendar.getInstance();
                endDateCal.setTime(endDate);
                time.put("start", staDateCal.get(Calendar.YEAR) + "-" + formatMonth(staDateCal.get(Calendar.MONTH) + 1) + "-" + dayFormat(staDateCal.get(Calendar.YEAR), staDateCal.get(Calendar.MONTH) + 1, start) + " 00:00:00");
                time.put("end", endDateCal.get(Calendar.YEAR) + "-" + formatMonth(endDateCal.get(Calendar.MONTH) + 1) + "-" + dayFormat(endDateCal.get(Calendar.YEAR), endDateCal.get(Calendar.MONTH) + 1, end) + " 23:59:59");
                timeList.add(time);
            } else {
                Date date = DateFormatUtil.addMonth(eData, i);
                Calendar dateCal = Calendar.getInstance();
                dateCal.setTime(date);
                int year = dateCal.get(Calendar.YEAR);
                int month = dateCal.get(Calendar.MONTH) + 1;
                time.put("start", dateCal.get(Calendar.YEAR) + "-" + formatMonth(dateCal.get(Calendar.MONTH) + 1) + "-" + dayFormat(year, month, 1) + " 00:00:00");
                time.put("end", dateCal.get(Calendar.YEAR) + "-" + formatMonth(dateCal.get(Calendar.MONTH) + 1) + "-" + dayFormat(year, month, null) + " 23:59:59");
                timeList.add(time);
                if (i == (interval - 1)) {
                    Map<String, String> time2 = new HashMap<>();
                    Date date2 = DateFormatUtil.addMonth(eData, interval);
                    Calendar dateCal2 = Calendar.getInstance();
                    dateCal2.setTime(date2);
                    int year2 = dateCal2.get(Calendar.YEAR);
                    int month2 = dateCal2.get(Calendar.MONTH) + 1;
                    time2.put("start", dateCal2.get(Calendar.YEAR) + "-" + formatMonth(dateCal2.get(Calendar.MONTH) + 1) + "-" + dayFormat(year2, month2, 1) + " 00:00:00");
                    time2.put("end", dateCal2.get(Calendar.YEAR) + "-" + formatMonth(dateCal2.get(Calendar.MONTH) + 1) + "-" + dayFormat(year2, month2, null) + " 23:59:59");
                    timeList.add(time2);
                }
            }
        }
        if (start >= end) {
            Date staaDate = DateFormatUtil.stringToDate(minTime, DateFormatUtil.yyyy_MM_dd_HH_mm_ss);
            Calendar staaDateCal = Calendar.getInstance();
            staaDateCal.setTime(staaDate);
            if (staaDateCal.get(Calendar.DAY_OF_MONTH) < start) {
                Map<String, String> time = new HashMap<>();
                Date staDate = DateFormatUtil.addMonth(eData, -1);
                Calendar staDateCal = Calendar.getInstance();
                staDateCal.setTime(staDate);
                time.put("start", staDateCal.get(Calendar.YEAR) + "-" + formatMonth(staDateCal.get(Calendar.MONTH) + 1) + "-" + dayFormat(staDateCal.get(Calendar.YEAR), staDateCal.get(Calendar.MONTH) + 1, start) + " 00:00:00");
                time.put("end", eDataCal.get(Calendar.YEAR) + "-" + formatMonth(eDataCal.get(Calendar.MONTH) + 1) + "-" + dayFormat(eDataCal.get(Calendar.YEAR), eDataCal.get(Calendar.MONTH) + 1, end) + " 23:59:59");
                timeList.add(time);
            }
            Date enddDate = DateFormatUtil.stringToDate(maxTime, DateFormatUtil.yyyy_MM_dd_HH_mm_ss);
            Calendar enddDateCal = Calendar.getInstance();
            enddDateCal.setTime(enddDate);
            if (enddDateCal.get(Calendar.DAY_OF_MONTH) > end) {
                Map<String, String> time = new HashMap<>();
                Date aData = DateFormatUtil.stringToDate(maxTime, DateFormatUtil.yyyy_MM_dd_HH_mm_ss);
                Calendar aDataCal = Calendar.getInstance();
                aDataCal.setTime(aData);
                Date endDate = DateFormatUtil.addMonth(aData, 1);
                Calendar endDateCal = Calendar.getInstance();
                endDateCal.setTime(endDate);
                time.put("start", aDataCal.get(Calendar.YEAR) + "-" + formatMonth(aDataCal.get(Calendar.MONTH) + 1) + "-" + dayFormat(aDataCal.get(Calendar.YEAR), aDataCal.get(Calendar.MONTH) + 1, start) + " 00:00:00");
                time.put("end", endDateCal.get(Calendar.YEAR) + "-" + formatMonth(endDateCal.get(Calendar.MONTH) + 1) + "-" + dayFormat(endDateCal.get(Calendar.YEAR), endDateCal.get(Calendar.MONTH) + 1, end) + " 23:59:59");
                timeList.add(time);
            }
        }
        return timeList;
    }

    private static String formatMonth(Integer moth) {
        if (moth.toString().length() == 1) {
            return "0" + moth;
        }
        return moth.toString();
    }

    /**
     * stopTime = 2019-05-27 00:00:00           stop + 申诉过期  <= now  申诉过期
     * now = 2019-05-29 00:00:00                stop + 复检过期  >= now  复检未过期
     * 申诉过期 = 1
     * 复检过期 = 1 + 1
     *
     * 专项质检   now - 复检过期 <= stopTime <= now - 申诉过期
     *
     * 自动质检    stopTime 不为空：now - 复检过期 <= stopTime <= now - 过期
     *           stopTime 为空：now - 复检过期 <= 周期的最后时间 <= now - 过期
     */
    @Scheduled(cron = "0 0 1 * * ?")
    public void cronWorkAppealVaild() {
        String logTxt = "【检查任务申诉过期-定时任务】";
        logger.info(logTxt + "启动");
        boolean start = true;
        try {
            start = FtpUtil.sendCcs("cronWorkAppealVaild", logTxt);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (!start) {
            logger.info(logTxt + "该方法其他机器有启动");
            return;
        }
        List<BusWorkWithBLOBs> works = new ArrayList<>();
        //申诉过期天数
        int appealInvalid = Integer.parseInt(sysConfigService.sysConfigGetByPK(Constants.APPEAL_MAX_DAY).getValue());
        //申诉过期日期
        Date appealInvalidDate = DateFormatUtil.addNDay(new Date(), -appealInvalid);
        logger.info(logTxt + "申诉过期日期" + DateFormatUtil.dateToString(appealInvalidDate, DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
        //复检过期天数
        int recheckInvalid = Integer.parseInt(sysConfigService.sysConfigGetByPK(Constants.RECHECK_MAX_DAY).getValue()) + appealInvalid;
        //复检过期日期
        Date recheckInvalidDate = DateFormatUtil.addNDay(new Date(), -recheckInvalid);
        logger.info(logTxt + "复检过期日期" + DateFormatUtil.dateToString(recheckInvalidDate, DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
        //专项质检
        BusWorkExample proExample = new BusWorkExample();
        proExample.createCriteria()
                .andWorktypeEqualTo(BaseEntity.PREQUALITY_PRE)
                .andStoptimeGreaterThanOrEqualTo(recheckInvalidDate)
                .andStoptimeLessThanOrEqualTo(appealInvalidDate);
        List<BusWorkWithBLOBs> proWorks = busWorkService.selectByExample(proExample);
        if (!proWorks.isEmpty()) {
            works.addAll(proWorks);
        }
        Long[] proIds = new Long[proWorks.size()];
        for (int i = 0; i < proWorks.size(); i++) {
            proIds[i] = proWorks.get(i).getId();
        }
        logger.info(logTxt + "专项质检任务ids" + Arrays.toString(proIds));
        //自动质检 && stoptime 不为空
        BusWorkExample autoExampleNot = new BusWorkExample();
        autoExampleNot.createCriteria()
                .andWorktypeEqualTo(BaseEntity.PREQUALITY_AUTO)
                .andStoptimeIsNotNull()
                .andStoptimeGreaterThanOrEqualTo(recheckInvalidDate)
                .andStoptimeLessThanOrEqualTo(appealInvalidDate);
        List<BusWorkWithBLOBs> autoWorks = busWorkService.selectByExample(autoExampleNot);
        if (!autoWorks.isEmpty()) {
            works.addAll(autoWorks);
        }
        Long[] autoIds = new Long[autoWorks.size()];
        for (int i = 0; i < autoWorks.size(); i++) {
            autoIds[i] = autoWorks.get(i).getId();
        }
        logger.info(logTxt + "自动质检stopTime不为空任务ids" + Arrays.toString(autoIds));
        if (works.isEmpty()) {
            return;
        }
        for (BusWorkWithBLOBs work : works) {
            BoolQueryBuilder boolQuery = new BoolQueryBuilder();
            boolQuery.must(
                    QueryBuilders.nestedQuery(
                            "workScores",
                            QueryBuilders.matchQuery("workScores.workId", work.getId()),
                            ScoreMode.None)
            );
            //总条数
            Integer sum = SystemStatic.crud.queryQBuilderAllByMes(SystemStatic.AUDIO_ES_INDEX, SystemStatic.AUDIO_ES_TYPE, boolQuery);
            logger.info(logTxt + "sum = " + sum);
            if (sum == 0) {
                continue;
            }
            //每次查询条数
            int excleMax = ConfigHelper.getInt("export.data.sheet.max.number", 1000);
            List<Integer> pageTount = TaskUtil.formatSum(sum, excleMax);//todo最后一个数字需要特殊处理:6022
            //分页查询数据
            //todo 有时间可以用script局部更新优化
            for (Integer pageNum : pageTount) {
                List<String> docList = SystemStatic.crud.queryMapQBuilderList(
                        SystemStatic.AUDIO_ES_INDEX,
                        SystemStatic.AUDIO_ES_TYPE,
                        pageNum,
                        excleMax,
                        boolQuery,
                        "",
                        ""
                );
                List<Source> sources = esUtil.strs2Entitys(docList);
                if (sources.isEmpty()) continue;
                for (Source source : sources) {
                    for (WorkScores workScores : source.getWorkScores()) {
                        if (workScores.getWorkId().toString().equals(work.getId().toString())) {
                            appealInvalTask(workScores);
                        }
                    }
                }
                esUtil.updateSources(sources);
            }
            if (busWorkService.updateByPrimaryKey(work) == 0) {
                logger.info(logTxt + "taskName = " + work.getWorkname() + "状态为【任务申诉复检过期】失败");
            } else {
                logger.info(logTxt + "taskName = " + work.getWorkname() + "状态为【任务申诉复检过期】成功");
            }
        }
        List<BusWork> worksNull = new ArrayList<>();
        //自动质检 && stoptime 为空
        BusWorkExample autoExampleNull = new BusWorkExample();
        autoExampleNull.createCriteria()
                .andWorktypeEqualTo(BaseEntity.PREQUALITY_AUTO)
                .andStoptimeIsNotNull();
        List<BusWorkWithBLOBs> autoWorksNull = busWorkService.selectByExample(autoExampleNull);
        if (!autoWorksNull.isEmpty()) {
            worksNull.addAll(autoWorksNull);
        }
        Long[] autoNullIds = new Long[worksNull.size()];
        for (int i = 0; i < worksNull.size(); i++) {
            autoNullIds[i] = worksNull.get(i).getId();
        }
        logger.info(logTxt + "自动质检stopTime为空任务ids" + Arrays.toString(autoNullIds));
        if (worksNull.isEmpty()) {
            return;
        }
        List<Map<String, String>> taskMap = new ArrayList<>();
        for (BusWork work : worksNull) {
            Map<String, String> map = new HashMap<>();
            map.put("taskId", work.getId().toString());
            int i = 0;
            while (true) {
                Date startDate = DateFormatUtil.addMonth(work.getOnsettime(), i);//周期的开始日期
                Date endDate = DateFormatUtil.addNDay(startDate, work.getEvalcycleend());//周期的最后日期
                if (
                        endDate.getTime() >= recheckInvalidDate.getTime() &&
                        endDate.getTime() <= appealInvalidDate.getTime()
                ) {
                    map.put("startTime", DateFormatUtil.dateToString(startDate, DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
                    map.put("endTime", DateFormatUtil.dateToString(endDate, DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
                } else {
                    break;
                }
                i++;
            }
            taskMap.add(map);
        }
        for (Map<String, String> map : taskMap) {
            BoolQueryBuilder boolQuery = new BoolQueryBuilder();
            boolQuery
                    .must(
                            QueryBuilders.nestedQuery(
                                    "workScores",
                                    QueryBuilders.matchQuery("workScores.workId", map.get("taskId")),
                                    ScoreMode.None)
                    )
                    .must(
                            QueryBuilders.rangeQuery("voiceInfo.callStartTime").gte(map.get("startTime")).lte(map.get("endTime"))
                    );
            //总条数
            Integer sum = SystemStatic.crud.queryQBuilderAllByMes(SystemStatic.AUDIO_ES_INDEX, SystemStatic.AUDIO_ES_TYPE, boolQuery);
            logger.info(logTxt + "sum = " + sum);
            if (sum == 0) {
                continue;
            }
            //每次查询条数
            int excleMax = ConfigHelper.getInt("export.data.sheet.max.number", 1000);
            List<Integer> pageTount = TaskUtil.formatSum(sum, excleMax);//todo最后一个数字需要特殊处理:6022
            //分页查询数据
            for (Integer pageNum : pageTount) {
                List<String> docList = SystemStatic.crud.queryMapQBuilderList(
                        SystemStatic.AUDIO_ES_INDEX,
                        SystemStatic.AUDIO_ES_TYPE,
                        pageNum,
                        excleMax,
                        boolQuery,
                        "",
                        ""
                );
                List<Source> sources = esUtil.strs2Entitys(docList);
                if (sources.isEmpty()) continue;
                for (Source source : sources) {
                    for (WorkScores workScores : source.getWorkScores()) {
                        if (workScores.getWorkId().toString().equals(map.get("taskId"))) {
                            appealInvalTask(workScores);
                        }
                    }
                }
                esUtil.updateSources(sources);
            }
        }
    }

    //申诉过期
    private static void appealInvalTask(WorkScores workScores) {
        int proStatus = workScores.getProStatus();
        switch (proStatus) {
            case BaseEntity.BIG_WORK_PROSTATUS_QUALITY_YES_0:
                workScores.setProStatus(BaseEntity.BIG_WORK_PROSTATUS_QUALITY_YES_IN_VALID_7);
                break;
            case BaseEntity.BIG_WORK_PROSTATUS_READ_YES_10:
                workScores.setProStatus(BaseEntity.BIG_WORK_PROSTATUS_READ_YES_IN_VALID_17);
                break;
        }
    }

    /**
     * stopTime = 2019-05-28 00:00:00           stop + 申诉过期  <= now  复检过期
     * now = 2019-05-29 00:00:00
     * 申诉过期 = 1
     * 复检过期 = 1 + 1
     *
     * 专项质检   stopTime <= now - 复检过期
     *
     * 自动质检    stopTime 不为空：stopTime <= now - 过期
     *           stopTime 为空：周期的最后时间 <= now - 过期
     */
    @Scheduled(cron = "0 30 1 * * ?")
    public void cronWorkRecheckVaild() {
        String logTxt = "【检查任务复检过期-定时任务】";
        logger.info(logTxt + "启动");
        boolean start = true;
        try {
            start = FtpUtil.sendCcs("cronWorkRecheckVaild", logTxt);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (!start) {
            logger.info(logTxt + "该方法其他机器有启动");
            return;
        }
        List<BusWorkWithBLOBs> works = new ArrayList<>();
        //申诉过期天数
        int appealInvalid = Integer.parseInt(sysConfigService.sysConfigGetByPK(Constants.APPEAL_MAX_DAY).getValue());
        //复检过期天数
        int recheckInvalid = Integer.parseInt(sysConfigService.sysConfigGetByPK(Constants.RECHECK_MAX_DAY).getValue()) + appealInvalid;
        Date recheckInvalidDate = DateFormatUtil.addNDay(new Date(), -recheckInvalid);
        logger.info(logTxt + "复检过期时间" + DateFormatUtil.dateToString(recheckInvalidDate, DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
        //专项质检
        BusWorkExample proExample = new BusWorkExample();
        proExample.createCriteria()
                .andWorktypeEqualTo(BaseEntity.PREQUALITY_PRE)
                .andStoptimeLessThanOrEqualTo(recheckInvalidDate);
        List<BusWorkWithBLOBs> proWorks = busWorkService.selectByExample(proExample);
        if (!proWorks.isEmpty()) {
            works.addAll(proWorks);
        }
        Long[] proIds = new Long[proWorks.size()];
        for (int i = 0; i < proWorks.size(); i++) {
            proIds[i] = proWorks.get(i).getId();
        }
        logger.info(logTxt + "专项质检任务ids" + Arrays.toString(proIds));
        //自动质检 && stoptime 不为空
        BusWorkExample autoExampleNot = new BusWorkExample();
        autoExampleNot.createCriteria()
                .andWorktypeEqualTo(BaseEntity.PREQUALITY_AUTO)
                .andStoptimeIsNotNull()
                .andStoptimeLessThanOrEqualTo(recheckInvalidDate);
        List<BusWorkWithBLOBs> autoWorks = busWorkService.selectByExample(autoExampleNot);
        if (!autoWorks.isEmpty()) {
            works.addAll(autoWorks);
        }
        Long[] autoIds = new Long[autoWorks.size()];
        for (int i = 0; i < autoWorks.size(); i++) {
            autoIds[i] = autoWorks.get(i).getId();
        }
        logger.info(logTxt + "自动质检stopTime不为空任务ids" + Arrays.toString(autoIds));
        if (works.isEmpty()) {
            return;
        }
        for (BusWorkWithBLOBs work : works) {
            BoolQueryBuilder boolQuery = new BoolQueryBuilder();
            boolQuery.must(QueryBuilders.nestedQuery("workScores", QueryBuilders.matchQuery("workScores.workId", work.getId()), ScoreMode.None));
            //总条数
            Integer sum = SystemStatic.crud.queryQBuilderAllByMes(SystemStatic.AUDIO_ES_INDEX, SystemStatic.AUDIO_ES_TYPE, boolQuery);
            logger.info(logTxt + "sum = " + sum);
            if (sum == 0) {
                continue;
            }
            //每次查询条数
            int excleMax = ConfigHelper.getInt("export.data.sheet.max.number", 1000);
            List<Integer> pageTount = TaskUtil.formatSum(sum, excleMax);//todo最后一个数字需要特殊处理:6022
            //分页查询数据
            //todo 有时间可以用script局部更新优化
            for (Integer pageNum : pageTount) {
                List<String> docList = SystemStatic.crud.queryMapQBuilderList(
                        SystemStatic.AUDIO_ES_INDEX,
                        SystemStatic.AUDIO_ES_TYPE,
                        pageNum,
                        excleMax,
                        boolQuery,
                        "",
                        ""
                );
                List<Source> sources = esUtil.strs2Entitys(docList);
                if (sources.isEmpty()) continue;
                for (Source source : sources) {
                    for (WorkScores workScores : source.getWorkScores()) {
                        if (workScores.getWorkId().toString().equals(work.getId().toString())) {
                            recheckInvalTask(workScores);
                        }
                    }
                }
                esUtil.updateSources(sources);
            }
            if (busWorkService.updateByPrimaryKey(work) == 0) {
                logger.info(logTxt + "taskName = " + work.getWorkname() + "状态为【任务申诉复检过期】失败");
            } else {
                logger.info(logTxt + "taskName = " + work.getWorkname() + "状态为【任务申诉复检过期】成功");
            }
        }
        List<BusWork> worksNull = new ArrayList<>();
        //自动质检 && stoptime 为空
        BusWorkExample autoExampleNull = new BusWorkExample();
        autoExampleNull.createCriteria()
                .andWorktypeEqualTo(BaseEntity.PREQUALITY_AUTO)
                .andStoptimeIsNotNull();
        List<BusWorkWithBLOBs> autoWorksNull = busWorkService.selectByExample(autoExampleNull);
        if (!autoWorksNull.isEmpty()) {
            worksNull.addAll(autoWorksNull);
        }
        Long[] autoNullIds = new Long[worksNull.size()];
        for (int i = 0; i < worksNull.size(); i++) {
            autoNullIds[i] = worksNull.get(i).getId();
        }
        logger.info(logTxt + "自动质检stopTime为空任务ids" + Arrays.toString(autoNullIds));
        if (worksNull.isEmpty()) {
            return;
        }
        List<Map<String, String>> taskMap = new ArrayList<>();
        for (BusWork work : worksNull) {
            Map<String, String> map = new HashMap<>();
            map.put("taskId", work.getId().toString());
            int i = 0;
            while (true) {
                Date startDate = DateFormatUtil.addMonth(work.getOnsettime(), i);//周期的开始日期
                Date endDate = DateFormatUtil.addNDay(startDate, work.getEvalcycleend());//周期的最后日期
                if (endDate.getTime() <= recheckInvalidDate.getTime()) {
                    map.put("startTime", DateFormatUtil.dateToString(startDate, DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
                    map.put("endTime", DateFormatUtil.dateToString(endDate, DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
                } else {
                    break;
                }
                i++;
            }
            taskMap.add(map);
        }
        for (Map<String, String> map : taskMap) {
            BoolQueryBuilder boolQuery = new BoolQueryBuilder();
            boolQuery
                    .must(
                            QueryBuilders.nestedQuery(
                                    "workScores",
                                    QueryBuilders.matchQuery("workScores.workId", map.get("taskId")),
                                    ScoreMode.None)
                    )
                    .must(
                            QueryBuilders.rangeQuery("voiceInfo.callStartTime").gte(map.get("startTime")).lte(map.get("endTime"))
                    );
            //总条数
            Integer sum = SystemStatic.crud.queryQBuilderAllByMes(SystemStatic.AUDIO_ES_INDEX, SystemStatic.AUDIO_ES_TYPE, boolQuery);
            logger.info(logTxt + "sum = " + sum);
            if (sum == 0) {
                continue;
            }
            //每次查询条数
            int excleMax = ConfigHelper.getInt("export.data.sheet.max.number", 1000);
            List<Integer> pageTount = TaskUtil.formatSum(sum, excleMax);//todo最后一个数字需要特殊处理:6022
            //分页查询数据
            for (Integer pageNum : pageTount) {
                List<String> docList = SystemStatic.crud.queryMapQBuilderList(
                        SystemStatic.AUDIO_ES_INDEX,
                        SystemStatic.AUDIO_ES_TYPE,
                        pageNum,
                        excleMax,
                        boolQuery,
                        "",
                        ""
                );
                List<Source> sources = esUtil.strs2Entitys(docList);
                if (sources.isEmpty()) continue;
                for (Source source : sources) {
                    for (WorkScores workScores : source.getWorkScores()) {
                        if (workScores.getWorkId().toString().equals(map.get("taskId"))) {
                            recheckInvalTask(workScores);
                        }
                    }
                }
                esUtil.updateSources(sources);
            }
        }
    }

    //复检过期
    private static void recheckInvalTask(WorkScores workScores) {
        int proStatus = workScores.getProStatus();
        switch (proStatus) {
            case BaseEntity.BIG_WORK_PROSTATUS_APPEAL_YES_20:
                workScores.setProStatus(BaseEntity.BIG_WORK_PROSTATUS_APPEAL_YES_IN_VALID_27);
                break;
            case BaseEntity.BIG_WORK_PROSTATUS_RECHECK_YES_30:
                workScores.setProStatus(BaseEntity.BIG_WORK_PROSTATUS_RECHECK_YES_IN_VALID_37);
                break;
        }
    }
}
